package com.ruoyi.wechat.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.wechat.common.Constants;
import com.ruoyi.wechat.common.ServiceException;
import com.ruoyi.wechat.config.DelayedOrder;
import com.ruoyi.wechat.config.OrderDelayQueue;
import com.ruoyi.wechat.config.WxPayV3Bean;
import com.ruoyi.wechat.domain.*;
import com.ruoyi.wechat.domain.dto.OrderDTO;
import com.ruoyi.wechat.domain.form.PlaceForm;
import com.ruoyi.wechat.domain.threads.AfterOrderHandle;
import com.ruoyi.wechat.mapper.AddrItemMapper;
import com.ruoyi.wechat.mapper.OrderMapper;
import com.ruoyi.wechat.service.*;
import com.ruoyi.wechat.utils.LoginHelper;
import com.ruoyi.wechat.utils.TimeUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单接口实现
 * </p>
 *
 * @author YinHeng
 * @since 2024/2/6
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Resource
    private IAppUserService wxUserService;
    @Autowired
    private IDelvTagService delvTagService;
    @Autowired
    private IUserAddrService userAddrService;
    @Autowired
    private AddrItemMapper addrItemMapper;
    @Autowired
    private IProductService productService;
    @Autowired
    private ISpecService specService;
    @Autowired
    private IOrderItemService orderItemService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private IOrderDelvService orderDelvService;
    @Autowired
    private OrderDelayQueue orderDelayQueue;
    @Autowired
    private IAttachItemService attachItemService;
    @Autowired
    private IOrderAttachService orderAttachService;
    @Autowired
    private IAppUserCouponService userCouponService;
    @Autowired
    private IAppCouponService couponService;
@Autowired
    private IAppVipService vipService;

    @Resource
    private WxPayV3Bean wxPayV3Bean;


    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Order place(PlaceForm req) {
        //创建订单
        Order order = new Order();
        BeanUtils.copyProperties(req, order);
        order.setTag(Constants.Order.TAG_0.getValue());

        //设置下单用户
        AppUser appUser = LoginHelper.getSession().getAppUser();
        order.setAccountUserId(appUser.getId());
        order.setAppUserId(appUser.getOpenid());

        //计算金额
        BigDecimal amount = BigDecimal.ZERO;
        List<OrderItem> orderItemList = new ArrayList<>();
        List<PlaceForm.Item> items = req.getItems();

        List<OrderAttach> orderAttachList = new ArrayList<>();
        //遍历购物车商品
        for (PlaceForm.Item reqItem : items) {
            LambdaQueryWrapper<Product> query = new LambdaQueryWrapper<>();
            Integer num = reqItem.getNum();
            //检查数量
            if (ObjectUtils.isEmpty(num)) {
                throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "商品数量为空");
            }
            query.eq(com.ruoyi.wechat.domain.Product::getId, reqItem.getId())
                    .eq(com.ruoyi.wechat.domain.Product::getOnOffStatus, Constants.Product.ON_OFF_STATUS_1.getValue());
            //todo 上锁
            Product product = productService.getOne(query);
            order.setCategory(product.getCategory());
            //检查商品
            if (ObjectUtils.isEmpty(product)) {
                throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "商品不存在");
            }
            LambdaQueryWrapper<Spec> specQuery = new LambdaQueryWrapper<>();
            specQuery.eq(Spec::getId, reqItem.getSpecId());
            specQuery.eq(Spec::getItemId, product.getId());
            Spec spec = specService.getOne(specQuery);
            if (ObjectUtils.isEmpty(spec)) {
                throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "商品规格不存在");
            }
            int stock = spec.getStock() - reqItem.getNum();
            if (stock < 0) {
                //todo 释放锁
                throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "商品库存不足");
            }
            //更新库存
            spec.setStock(stock);
            specService.updateById(spec);
            //todo 释放锁

            //商品单价
            BigDecimal price = spec.getPriceNormal();
            //计算附加服务费用
            List<AttachItem> attachList = req.getProductAttachList();
            if (!ObjectUtils.isEmpty(attachList)) {
                List<Long> attachIds = attachList.stream().map(AttachItem::getId).collect(Collectors.toList());
                BigDecimal attachPrice = BigDecimal.ZERO;
                LambdaQueryWrapper<AttachItem> attachQuery = new LambdaQueryWrapper<>();
                attachQuery.eq(AttachItem::getEnable, Constants.Common.STATUS_1.getValue());
                attachQuery.eq(AttachItem::getType, Constants.AttachItem.TYPE_4.getValue());
                attachQuery.eq(AttachItem::getItemId, product.getId());
                attachQuery.in(AttachItem::getId, attachIds);
                //根据选中附加服务计算附加服务的价格
                List<AttachItem> attachItemList = attachItemService.list(attachQuery);
                //附加服务不为空，则加上附加服务的价格
                if (!ObjectUtils.isEmpty(attachItemList)) {
                    for (AttachItem attach : attachItemList) {
                        attachPrice = attachPrice.add(attach.getPrice());
                        //顺便记录订单的附加服务项
                        OrderAttach orderAttach = new OrderAttach();
                        orderAttach.setAttachItemId(attach.getItemId());
                        orderAttach.setAttachName(attach.getName());
                        orderAttach.setAttachType(attach.getType());
                        orderAttach.setAttachId(attach.getId());
                        orderAttach.setAttachPrice(attach.getPrice());
                        orderAttachList.add(orderAttach);
                    }

                    order.setTag(Constants.Order.TAG_1.getValue());
                }
                //单价+附加服务价格 再*数量
                price = price.add(attachPrice);
            }

            //商品总价=商品单价 * 下单数量 - 优惠券面值
            price = price.multiply(BigDecimal.valueOf(num));
            //如果勾选了优惠券，则总金额减掉优惠券金额
            if (!ObjectUtils.isEmpty(req.getUserCouponId())){
                AppUserCoupon userCoupon = userCouponService.selectAppUserCouponById(req.getUserCouponId());
                //如果优惠券为空或用户id不相等
                if (ObjectUtils.isEmpty(userCoupon) || !appUser.getId().equals(userCoupon.getUserId())){
                    throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,"优惠券不可用");
                }
                if (userCoupon.getNum() <= 0){
                    throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,"优惠券已用完");
                }
                AppCoupon coupon = couponService.selectAppCouponById(userCoupon.getCouponId());
                price = price.subtract(coupon.getAmount());
                //更新优惠券数量
                userCoupon.setNum(userCoupon.getNum()-1);
                userCouponService.updateAppUserCoupon(userCoupon);
                //订单设置优惠券ID
                order.setCouponId(coupon.getId());
                order.setCouponTitle(coupon.getTitle());
                order.setCouponAmt(coupon.getAmount());
            }
            //如果减扣后的价格小于0，则设置为0
            if (price.compareTo(BigDecimal.ZERO) <= 0 ){
                price = BigDecimal.ZERO;
            }
            //如果用户是会员，则进行打折计算
            if (!ObjectUtils.isEmpty(appUser.getVipId())){
                AppVip appVip = vipService.selectAppVipById(appUser.getVipId());
                if (!ObjectUtils.isEmpty(appVip)){
                    price = price.multiply(appVip.getDiscount());
                    //订单设置会员信息
                    order.setVipId(appVip.getId());
                    order.setVipTitle(appVip.getTitle());
                    order.setVipDiscountAmt(appVip.getDiscount());
                }
            }
            //订单总金额
            amount = amount.add(price);

            //设置订单详情
            OrderItem orderItem = new OrderItem();
            //封面
            orderItem.setCover(product.getCover());
            //数量
            orderItem.setNum(reqItem.getNum());
            //描述
            orderItem.setDescr(product.getDescr());
            //该商品合计价格
            orderItem.setCountPrice(price);
            //商品ID
            orderItem.setProductId(product.getId());
            //商品名称
            orderItem.setProductName(product.getName());
            //商品单价
            orderItem.setUnitPrice(spec.getPriceNormal());
            //商品规格ID
            orderItem.setSpecId(spec.getId());
            orderItemList.add(orderItem);
        }

        //设置订单金额
        order.setTotalAmount(amount);
        order.setRealPayAmount(amount);

        //设置收获地址
        LambdaQueryWrapper<UserAddr> uAddrQuery = new LambdaQueryWrapper<>();
        uAddrQuery.eq(UserAddr::getId, req.getAddrId());
        uAddrQuery.eq(UserAddr::getUserId, appUser.getId());
        UserAddr userAddr = userAddrService.getOne(uAddrQuery);
        if (ObjectUtils.isEmpty(userAddr)) {
            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "请先设置配送地址");
        }
        order.setAddrId(userAddr.getId());
        String addrText = userAddr.getArea() + "/" + userAddr.getComy() + userAddr.getRidgepole() + userAddr.getDoor();
        order.setAddrDetail(addrText);
        order.setUNick(userAddr.getNick());
        order.setUPhone(userAddr.getPhone());

        //设置配送地址和派单给哪个部门
        AddrItem addrItem = addrItemMapper.selectById(userAddr.getAddrId());
        if (addrItem == null) {
            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "地址选项不存在");
        }
        order.setDeptId(addrItem.getDeptId());

        //设置附件集合
        order.setAttachFiles(JSONObject.toJSONString(req.getAttachFileList()));
        //处理预约时间
        if ((!ObjectUtils.isEmpty(req.getAptTime().trim()))) {
            LocalDateTime aptTime = LocalDateTime.parse(req.getAptTime(), formatter);
            order.setAptTime(aptTime);
        }
        //生成订单号
        String tradeNo = OrderIdUtils.genOrderNum(wxPayV3Bean.getMchId());
        order.setTradeNo(tradeNo);

        //下单时间
        order.setCreateTime(LocalDateTime.now());
        //配送方式
        order.setDelvMode(req.getDelvMode());
        order.setPayStatus(Constants.Order.PAY_STATUS_1.getValue());
        order.setDelvStatus(Constants.Order.DELV_STATUS_1.getValue());

        //保存主订单
        this.save(order);

        orderItemList.forEach(orderItem -> {
            orderItem.setOrderId(order.getId());
        });
        //订单项批量保存
        orderItemService.saveBatch(orderItemList);

        //保存附加服务
        if (!ObjectUtils.isEmpty(orderAttachList)) {
            orderAttachList.forEach(item -> {
                item.setOrderId(order.getId());
            });
        }
        orderAttachService.saveBatch(orderAttachList);


        //取快递则设置配送初始化信息
        if (Constants.Order.CATEGORY_1.getValue().equals(order.getCategory())) {
            AfterOrderHandle after = new AfterOrderHandle(productService, userAddrService, addrItemMapper, orderDelvService, delvTagService, specService, order, orderItemList);
            Thread thread = new Thread(after);
            thread.start();
        }
        //订单加入延迟队列
        DelayedOrder delayedOrder = new DelayedOrder(this, order.getTradeNo(), Constants.DELAYED_TIME);
        orderDelayQueue.addOrderToQueue(delayedOrder);

        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void canCel(String tradeNo) {
        LambdaQueryWrapper<Order> orderQuery = new LambdaQueryWrapper<>();
        orderQuery.eq(Order::getTradeNo, tradeNo);
        Order order = this.getOne(orderQuery);
        if (Constants.Order.PAY_STATUS_3.getValue().equals(order.getPayStatus())) {
            return;
        }
        //支付状态：取消支付
        order.setPayStatus(Constants.Order.PAY_STATUS_4.getValue());
        //订单状态：已关闭
        order.setStatus(Constants.Common.STATUS_1.getValue());

        LambdaQueryWrapper<OrderItem> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.eq(OrderItem::getOrderId, order.getId());
        List<OrderItem> itemList = orderItemService.list(itemQuery);

        //获取订单子项
        Map<Long, OrderItem> itemMap = new HashMap<>();
        for (OrderItem item : itemList) {
            itemMap.put(item.getSpecId(), item);
        }

        LambdaQueryWrapper<Spec> specQuery = new LambdaQueryWrapper<>();
        specQuery.in(Spec::getId, itemMap.keySet());
        List<Spec> specList = specService.list(specQuery);

        //返回库存
        for (Spec spec : specList) {
            OrderItem item = itemMap.get(spec.getId());
            spec.setStock(spec.getStock() + item.getNum());
        }
        this.updateById(order);
        specService.updateBatchById(specList);
    }

    @Override
    public List<OrderDTO> searchList(Order form) {
        AppUser appUser = LoginHelper.getSession().getAppUser();
        LambdaQueryWrapper<Order> query = new LambdaQueryWrapper<>();

        query.eq(Order::getAccountUserId, appUser.getId())
                .ne(Order::getStatus, Constants.Common.STATUS_1.getValue())
                .orderByDesc(Order::getCreateTime);

        //根据用户id查订单列表
        List<Order> orderList = this.list(query);
        if (orderList.size() == 0) {
            return new ArrayList<>();
        }

        List<Long> orderIds = orderList.stream().map(Order::getId).collect(Collectors.toList());

        LambdaQueryWrapper<UserAddr> userAddrQuery = new LambdaQueryWrapper<>();
        userAddrQuery.eq(UserAddr::getUserId, appUser.getId());
        //查询用户地址集合
        List<UserAddr> appUserAddrList = userAddrService.list(userAddrQuery);
        HashMap<Long, UserAddr> userAddrMap = new HashMap<>();
        appUserAddrList.forEach(userAddr -> {
            userAddrMap.put(userAddr.getId(), userAddr);
        });

        //查询地址选项集合
        List<AddrItem> appAddrItems = addrItemMapper.selectList(new QueryWrapper<>());
        Map<Long, AddrItem> addrItemMap = new HashMap<>();
        appAddrItems.forEach(addrItem -> {
            addrItemMap.put(addrItem.getId(), addrItem);
        });
        //查询子订单集合
        LambdaQueryWrapper<OrderItem> orItemQuery = new LambdaQueryWrapper<>();
        orItemQuery.in(OrderItem::getOrderId, orderIds);
        List<OrderItem> orderItems = orderItemService.list(orItemQuery);
        //子订单分组保存
        Map<Long, List<OrderItem>> itemMap = new HashMap<>();
        orderItems.forEach(item -> {
            List<OrderItem> itemList = itemMap.get(item.getOrderId());
            if (ObjectUtils.isEmpty(itemList)) {
                itemList = new ArrayList<>();
            }
            itemList.add(item);
            itemMap.put(item.getOrderId(), itemList);
        });
        //构造订单传输对象
        List<OrderDTO> dtoList = new ArrayList<>();
        orderList.forEach(item -> {
            OrderDTO dto = new OrderDTO();
            BeanUtils.copyProperties(item, dto);
            //取件截图列表
            String attachFiles = dto.getAttachFiles();
            if (!ObjectUtils.isEmpty(attachFiles)) {
                List<String> list = JSONObject.parseObject(attachFiles, new TypeReference<List<String>>() {
                });
                dto.setAttachFileList(list);
            }
            //送达照片
            String arrivePhotos = item.getArrivePhotos();
            List<String> arrivePhotoList = new ArrayList<>();
            try {
                arrivePhotoList = JSONObject.parseObject(arrivePhotos, new TypeReference<List<String>>() {
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
            dto.setArrivePhotoList(arrivePhotoList);
            //拆分地址
            UserAddr userAddr = userAddrMap.get(item.getAddrId());
            if (!ObjectUtils.isEmpty(userAddr)) {
                dto.setAddrPhone(userAddr.getPhone());
                dto.setAddrNick(userAddr.getNick());
                dto.setArea(userAddr.getArea());
                dto.setComy(userAddr.getComy());
                dto.setRidgepole(userAddr.getRidgepole());
                dto.setDoor(userAddr.getDoor());
            }

            //统计商品数量
            List<OrderItem> appOrderItems = itemMap.get(item.getId());
            Integer totalNum = 0;
            for (int i = 0; i < appOrderItems.size(); i++) {
                totalNum += appOrderItems.get(i).getNum();
            }
            dto.setTotalNum(totalNum);
            //获取驿站标签
            LambdaQueryWrapper<DelvTag> tagQuery = new LambdaQueryWrapper<>();
            tagQuery.eq(DelvTag::getOrderId, item.getId());
            List<DelvTag> tagList = delvTagService.list(tagQuery);
            tagList.forEach(tag -> {
                String urls = tag.getUrls();
                try {
                    ArrayList<String> urlList = JSONObject.parseObject(urls, new TypeReference<ArrayList<String>>() {
                    });
                    tag.setUrlList(urlList);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            dto.setTagList(tagList);
            //获取配送数据
            LambdaQueryWrapper<OrderDelv> delvQuery = new LambdaQueryWrapper<>();
            delvQuery.eq(OrderDelv::getOrderId, item.getId());
            List<OrderDelv> delvList = orderDelvService.list(delvQuery);
            dto.setDelvList(delvList);
            //如果配送未结束，则计算花费时间
            if (Constants.Order.DELV_STATUS_4.getValue().equals(item.getDelvStatus())
                    || Constants.Order.DELV_STATUS_5.getValue().equals(item.getDelvStatus())) {
                dto.setCostTime(TimeUtils.costTime(item.getCreateTime(), item.getArriveTime()));
            } else {
                dto.setCostTime(TimeUtils.costTime(item.getCreateTime()));
            }
            //子订单集合
            dto.setItemList(itemMap.get(item.getId()));
            //计算耗时
            dtoList.add(dto);
        });

        return dtoList;
    }

    @Override
    public OrderDTO detail(Order form) {
        AppUser appUser = LoginHelper.getSession().getAppUser();
        Order order = this.getById(form.getId());
        //不是自己的不能看
        if (!appUser.getOpenid().equals(order.getAppUserId())
                && !appUser.getId().equals(Long.valueOf(order.getAppUserId()))) {
            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "没有权限");
        }

        OrderDTO dto = new OrderDTO();
        BeanUtils.copyProperties(order, dto);
        //取件截图列表
        String attachFiles = dto.getAttachFiles();
        if (!ObjectUtils.isEmpty(attachFiles)) {
            List<String> list = JSONObject.parseObject(attachFiles, new TypeReference<List<String>>() {
            });
            dto.setAttachFileList(list);
        }
        //送达照片
        String arrivePhotos = order.getArrivePhotos();
        List<String> arrivePhotoList = new ArrayList<>();
        try {
            arrivePhotoList = JSONObject.parseObject(arrivePhotos, new TypeReference<List<String>>() {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        dto.setArrivePhotoList(arrivePhotoList);
        //拆分地址
        UserAddr userAddr = userAddrService.getById(order.getAddrId());
        if (!ObjectUtils.isEmpty(userAddr)) {
            dto.setAddrPhone(userAddr.getPhone());
            dto.setAddrNick(userAddr.getNick());
            dto.setArea(userAddr.getArea());
            dto.setComy(userAddr.getComy());
            dto.setRidgepole(userAddr.getRidgepole());
            dto.setDoor(userAddr.getDoor());
        }

        //统计商品数量
        LambdaQueryWrapper<OrderItem> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.eq(OrderItem::getOrderId, order.getId());
        List<OrderItem> appOrderItems = orderItemService.list(itemQuery);
        Integer totalNum = 0;
        for (int i = 0; i < appOrderItems.size(); i++) {
            totalNum += appOrderItems.get(i).getNum();
        }
        dto.setTotalNum(totalNum);
        //获取驿站标签
        LambdaQueryWrapper<DelvTag> tagQuery = new LambdaQueryWrapper<>();
        tagQuery.eq(DelvTag::getOrderId, order.getId());
        List<DelvTag> tagList = delvTagService.list(tagQuery);
        tagList.forEach(tag -> {
            String urls = tag.getUrls();
            try {
                ArrayList<String> urlList = JSONObject.parseObject(urls, new TypeReference<ArrayList<String>>() {
                });
                tag.setUrlList(urlList);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });
        dto.setTagList(tagList);
        //获取配送数据
        LambdaQueryWrapper<OrderDelv> delvQuery = new LambdaQueryWrapper<>();
        delvQuery.eq(OrderDelv::getOrderId, order.getId());
        List<OrderDelv> delvList = orderDelvService.list(delvQuery);
        dto.setDelvList(delvList);
        //如果配送未结束，则计算花费时间
        if (Constants.Order.DELV_STATUS_4.getValue().equals(order.getDelvStatus())
                || Constants.Order.DELV_STATUS_5.getValue().equals(order.getDelvStatus())) {
            dto.setCostTime(TimeUtils.costTime(order.getCreateTime(), order.getArriveTime()));
        } else {
            dto.setCostTime(TimeUtils.costTime(order.getCreateTime()));
        }
        return dto;
    }

}
